// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Tools.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Triangulations_2/Py_Tools.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================
// include ====================================================================
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <include/iterator.h>
#include <CGAL/Object.h>

#include <CGAL/Triangulation_2.h>
#include <CGAL/Constrained_triangulation_plus_2.h>

#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Triangulation_hierarchy_vertex_base_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>

#include <boost/python.hpp>
#include <boost/cstdint.hpp>


using boost::python::object;

//BEGIN functions of Vertex Class ========================================
template <class Vertex_handle> 
object point(Vertex_handle& vh)
{
	return object(vh->point());
}
template <class Vertex_handle> 
object py_info(const Vertex_handle& vh)
{
	return object(vh->info());
}
template <class Vertex_handle> 
void set_info(Vertex_handle& vh,const object& py_obj)
{
	vh->info() = py_obj;
}
template <class Vertex_handle,class Point_2> 
void set_point(Vertex_handle& vh,const Point_2& pt)
{
	vh->set_point(pt);
}
template <class Vertex_handle> 
bool is_valid(const Vertex_handle& vh)
{
	return vh->is_valid();
}
template <class Vertex_handle> 
int degree(const Vertex_handle& vh)
{
	return vh->degree();
}

template <class Vertex_handle,class Face> 
Face face(Vertex_handle& vh)
{
	return vh->face();
}

//END of Vertex functions ================================================

//BEGIN list of Face functions============================================
template <class Face_handle> 
int py_ccw(const Face_handle& fh,int i)
{
	return fh->ccw(i);
}
template <class Face_handle> 
int py_cw(const Face_handle& fh,int i)
{
	return fh->cw(i);
}
template <class Face_handle,class Vertex_handle> 
Vertex_handle py_mirror_vertex(const Face_handle& fh,int i)
{
	return fh->mirror_vertex(i);
}
template <class Face_handle> 
int py_mirror_index(const Face_handle& fh,int i)
{
	return fh->mirror_index(i);
}
template <class Face_handle,class Vertex_handle> 
Vertex_handle py_vertex(const Face_handle& fh,int i)
{
	return fh->vertex(i);
}
template <class Face_handle,class Vertex_handle> 
bool py_has_vertex1(const Face_handle& fh,Vertex_handle v)
{
	return fh->has_vertex(v);
}
template <class Face_handle,class Vertex_handle> 
bool py_has_vertex2(const Face_handle& fh,Vertex_handle v,int i)
{
	return fh->has_vertex(v,i);
}
template <class Face_handle,class Vertex_handle> 
int py_index1(const Face_handle& fh,Vertex_handle v)
{
	return fh->index(v);
}
template <class Face_handle> 
int py_index2(const Face_handle& fh,Face_handle f)
{
	return fh->index(f);
}
template <class Face_handle> 
Face_handle py_neighbor(const Face_handle& fh,int i)
{
	return fh->neighbor(i);
}
template <class Face_handle> 
bool py_has_neighbor1(const Face_handle& fh,Face_handle f)
{
	return fh->has_neighbor(f);
}
template <class Face_handle> 
bool py_has_neighbor2(const Face_handle& fh,Face_handle f,int& i)
{
	return fh->has_neighbor(f,i);
}
template <class Face_handle> 
void py_set_vertices1(Face_handle& fh)
{
	fh->set_vertices();
}
template <class Face_handle,class Vertex_handle> 
void py_set_vertices2(Face_handle& fh,Vertex_handle v1,Vertex_handle v2,Vertex_handle v3)
{
	fh->set_vertices(v1,v2,v3);
}
template <class Face_handle,class Vertex_handle> 
void py_set_vertex(Face_handle& fh,int i,Vertex_handle v)
{
	fh->set_vertex(i,v);
}
template <class Face_handle> 
void py_set_neighbor(Face_handle& fh,int i,Face_handle n)
{
	fh->set_neighbor(i,n);
}
template <class Face_handle> 
void py_set_neighbors1(Face_handle& fh)
{
	fh->set_neighbors();
}
template <class Face_handle> 
void py_set_neighbors2(Face_handle& fh,Face_handle n0, Face_handle n1, Face_handle n2)
{
	fh->set_neighbors(n0,n1,n2);
}
template <class Face_handle> 
void py_reorient(Face_handle& fh)
{
	fh->reorient();
}
template <class Face_handle> 
void py_ccw_permute(Face_handle& fh)
{
	fh->ccw_permute();
}
template <class Face_handle> 
void py_cw_permute(Face_handle& fh)
{
	fh->cw_permute();
}
template <class Face_handle> 
int py_dimension(Face_handle& fh)
{
	return fh->dimension();
}
template <class Face_handle> 
bool py_is_constrained(const Face_handle& fh,int i)
{
	return fh->is_constrained(i);
}
//END list of Face functions============================================

template<typename T>
object py_first(const T& t)
{
	return object(t.first);
}
template<typename T>
object second(const T& t)
{
  return object(t.second);
}

template < class iterator,class Context>
simple_python_iterator<iterator> vertices_of_Context(Context& context)
{
	std::pair< iterator , iterator > p( context.vertices_begin(), context.vertices_end() );
	return simple_python_iterator<iterator>(p);
}

//exporting tools of Triangulations.========================
template <class kernel > 
void Py_Tools()
{
	using namespace boost::python;
	// three things must be fixed in order to insure the derivation in the python side.
	// -1: the vertex_base 
	// -2: the face_base
	// -3: the data_structure
	typedef CGAL::Alpha_shape_vertex_base_2<kernel> 	Avb;
	typedef CGAL::Triangulation_hierarchy_vertex_base_2<Avb> Hv; //this one is needed when the input data set is huge for the Alpha_shape_2,
																 // say more than 10.000 points,
	typedef CGAL::Triangulation_vertex_base_with_info_2<boost::python::object,kernel,Hv> 	Vb;

	typedef CGAL::Delaunay_mesh_face_base_2<kernel> 	Mf; 
	typedef CGAL::Alpha_shape_face_base_2<kernel,Mf> 	Af;

	typedef CGAL::Triangulation_data_structure_2<Vb,Af> Tds;

	typedef CGAL::Triangulation_2<kernel,Tds>   				Triangulation_2;

	typedef typename Triangulation_2::Face 						Face;
	typedef typename Triangulation_2::Face_handle 				Face_handle;
	typedef typename Triangulation_2::Finite_faces_iterator 	Face_iterator;
	typedef typename Triangulation_2::Face_circulator			Face_circulator;
	typedef typename Triangulation_2::Line_face_circulator		Line_face_circulator;

	typedef typename std::list<Face_handle>::iterator  			OutputItFaces;

	typedef typename Triangulation_2::All_faces_iterator 		All_faces_iterator;

	typedef typename Triangulation_2::Vertex 					Vertex;
	typedef typename Triangulation_2::Finite_vertices_iterator 	Vertex_iterator;
	typedef typename Triangulation_2::Vertex_handle 			Vertex_handle;
	typedef typename Triangulation_2::All_vertices_iterator 	All_vertices_iterator;
	typedef typename Triangulation_2::Vertex_circulator 		Vertex_circulator;

	typedef typename kernel::Point_2 							Point_2;

	typedef typename Triangulation_2::Edge 						Edge;
	typedef typename Triangulation_2::All_edges_iterator 		All_edges_iterator;
	typedef typename Triangulation_2::Edge_circulator			Edge_circulator;
	typedef typename std::list<Edge>::iterator  				OutputItEdges;

	typedef CGAL::Exact_predicates_tag 													Exact_predicates_tag;
	typedef CGAL::Constrained_triangulation_2<kernel,Tds,Exact_predicates_tag>   		Constrained_triangulation_2;
	typedef typename Constrained_triangulation_2::Constraint							Constraint;

	typedef CGAL::Constrained_triangulation_plus_2<Constrained_triangulation_2>   		Constrained_triangulation_plus_2;
	typedef typename Constrained_triangulation_plus_2::Context							Context;
	typedef typename Constrained_triangulation_plus_2::Vertices_in_constraint_iterator	Vertices_in_constraint_iterator;


// 	simple_python_iterator<OutputItEdges>::declare("OutputItEdges","\n\niterator over edges");
// 	simple_python_iterator<OutputItFaces>::declare("OutputItFaces","\n\niterator over faces");
	

const char* Vertex_doc ="\
Handles are widely used in cgal to allow access to vertices, faces and cells\n\
Vertex class correponds to cgal's C++ Vertex_handle concept.\n\
So it's not used directly, but related to the Trinagulations";

	class_<Vertex_handle>("Vertex",Vertex_doc,init<>())
		.def(init< const Vertex_iterator& >())
		.def(self==self)
		.def(self!=self)
		.def(self < self)
		.def("point",&point<Vertex_handle>,"v.point(self) -> Point_2\nReturns the point stored in the vertex v")
		.def("is_valid",&is_valid<Vertex_handle>,"v.is_valid(self) -> bool\n")
		.def("set_point",&set_point<Vertex_handle,Point_2>,"v.set_point(self, Point_2 p) -> Stores the point p in the vertex v")
		.def("info",&py_info<Vertex_handle>,"v.info(self) -> Returns the info stored in the vertex v\nthis info may be any python object")
		.def("set_info",&set_info<Vertex_handle>,"v.set_info(self,object) -> Sets object as information for the vertex v\nthis info may be any python object")
		.def("degree",&degree<Vertex_handle>,"v.degree(self) -> int\nReturns the degree of the vertex v.")
		.def("face",&face<Vertex_handle,Face_handle>,"v.face(self) -> Face\nReturns the incident face of v.")
	;

	// Face_handle Class.
const char* Face_doc ="\
Handles are widely used in cgal to allow access to vertices, faces and cells\n\
Face class correponds to cgal's C++ Face_handle concept.\n\
So it's not used directly, but related to the Trinagulations";

const char* vertex_doc="\
f.vertex(self ,int i) -> Vertex\n\n\
returns the vertex i of f .\nPrecondition: 0 <= i <= 2.";

const char* has_vertex_doc="\
f.has_vertex(self,Vertex v) -> bool\n\n\
returns true if v is a vertex of f .";

const char* index_doc="\
f.index(self,Vertex v) -> int\n\
returns the index of v in f .\n\n\
f.index(self,Face v) -> int\n\
returns the index of neighbor n in f.";

const char* neighbor_doc="\
f.neighbor(self,int i) -> Face\n\
returns the neighbor i of f .\n\
Precondition: 0 <= i <= 2";

const char* has_neighbor_doc="\
f.has_neighbor (self,Face n) -> bool\n\
returns true if n is a neighbor of f.";

const char* set_vertices_doc="\
f.set_vertices(self) -> void\nsets the vertices to Vertex_handle().\n\
f.set_vertices (self, Vertex v0,Vertex v1,Vertex v2) -> void\nsets the vertices.";

const char* set_vertex_doc="\
f.set_vertex(self ,int i, Vertex v) -> sets vertex i to v.\n\
Precondition: 0 <= i <= 2.";

const char* set_neighbor_doc="\
f.set_neighbor(self ,int i, Face n) -> sets neighbors i to n.\n\
Precondition: 0 <= i <= 2.";

const char* set_neighbors_doc="\
f.set_neighbors(self) -> sets the neighbors to Face()\n\
f.set_neighbors(self ,Face n0,Face n1,Face n2) -> sets the neighbors";

const char* reorient_doc="\
f.reorient(self) -> Changes the orientation of f by exchanging vertex(0) with vertex(1) and neighbor(0) with neighbor(1).";

const char* ccw_permute_doc="\
f.ccw_permute(self) -> preforms a counterclockwise permutation of the vertices and neighbors of f.";

const char* cw_permute_doc="\
f.cw_permute(self) -> preforms a clockwise permutation of the vertices and neighbors of f.";

const char* dimension_doc="f.dimension(self) -> int\nreturns the dimension.";
const char* is_constrained_doc="f.is_constrained(self,i) -> bool\n tests if the Edge(f,i) is constrained";

	class_<Face_handle>("Face",Face_doc,init<>())
		.def(init< const Face_iterator& >()) 
		.def(self==self)
		.def(self!=self)
		.def(self < self)
		.def("ccw",&py_ccw<Face_handle>)
		.def("cw",&py_cw<Face_handle>)
		.def("mirror_vertex",&py_mirror_vertex<Face_handle,Vertex_handle>)
 		.def("mirror_index",&py_mirror_index<Face_handle>)
		.def("vertex",&py_vertex<Face_handle,Vertex_handle>,vertex_doc)
		.def("has_vertex",&py_has_vertex1<Face_handle,Vertex_handle>,has_vertex_doc)
// 		.def("has_vertex",&py_has_vertex2<Face_handle,Vertex_handle>)
		.def("index",&py_index1<Face_handle,Vertex_handle>,index_doc)
		.def("index",&py_index2<Face_handle>)
		.def("neighbor",&py_neighbor<Face_handle>,neighbor_doc)
		.def("has_neighbor",&py_has_neighbor1<Face_handle>,has_neighbor_doc)
// 		.def("has_neighbor",&py_has_neighbor2<Face_handle>)
		.def("set_vertices",&py_set_vertices1<Face_handle>,set_vertices_doc)
		.def("set_vertices",&py_set_vertices2<Face_handle,Vertex_handle>)
		.def("set_vertex",&py_set_vertex<Face_handle,Vertex_handle>,set_vertex_doc)
		.def("set_neighbor",&py_set_neighbor<Face_handle>,set_neighbor_doc)
		.def("set_neighbors",&py_set_neighbors1<Face_handle>,set_neighbors_doc)
		.def("set_neighbors",&py_set_neighbors2<Face_handle>)
		.def("reorient",&py_reorient<Face_handle>,reorient_doc)
		.def("ccw_permute",&py_ccw_permute<Face_handle>,ccw_permute_doc)
		.def("cw_permute",&py_cw_permute<Face_handle>,cw_permute_doc)
		.def("dimension",&py_dimension<Face_handle>,dimension_doc)
		.def("is_constrained",&py_is_constrained<Face_handle>,is_constrained_doc)
	;
	//	Edge Class.
	class_<Edge>("Edge","Is a pair of Face and the index of its incident vertex",init<>())
		.def(init< const Face_handle&,int >("e = Edge(Face f,int i)\nIntroduces an edge(f,i)"))
		.def("face",&py_first<Edge>,"e.face(self) -> Face")
 		.def("vertex",&second<Edge>,"e.vertex(self) -> int")
		.def(self==self)
		.def(self!=self)
		.def(self < self)
	;


	class_<Constraint>("Constraint","Is a pair of two Point_2",init<>())
		.def(init< const Point_2&,const Point_2& >("c = Constraint(Point_2 p,Point_2 q)\nIntroduces a Constraint pq."))
		.def("first",&py_first<Constraint>,"c.first(self) -> Point_2\n")
 		.def("second",&second<Constraint>,"c.second(self) -> Point_2\n")
		.def(self==self)
		.def(self!=self)
		.def(self < self)
	;

const char* Context_doc="\
This type is intended to describe a constraint enclosing a subconstraint and the position \n\
of the subconstraint in this constraint.";

	class_<Context>("Context",Context_doc,init<>())
		.def("number_of_vertices",&Context::number_of_vertices)
		.add_property("vertices",&vertices_of_Context<Vertices_in_constraint_iterator,Context>)
	;
//====================================================
}

extern void export_Triangulation_vertex_base_with_info_2();

void export_Tools()
{
	Py_Tools<K>();
}
